package test;

import org.assertj.core.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.net.util.IPAddressUtil;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by pt on 16-4-12.
 */
public class Ipstock {
    private Logger logger = LoggerFactory.getLogger(Ipstock.class);
    Region[] regions;

    public String findRegionId(String ipv4){
        Region region = findRegion(ipv4);
        if(region == null)
            return null;
        return region.regionId;
    }

    public Region findRegion(String ipv4){
        if(ipv4 == null)
            return null;
        byte[] formatV4 = IPAddressUtil.textToNumericFormatV4(ipv4);
        if(formatV4 == null)
            return null;
        int ip = ByteBuffer.wrap(formatV4).getInt();
        int low = 0;
        int high = regions.length;
        while(low <= high){
            int middle = (low + high) >>> 1;
            Region r = regions[middle];
            if(ip < r.startIp){
                high = middle - 1;
            }else if( ip > r.endIp){
                low = middle + 1;
            }else {
                return r;
            }
        }
        return null;
    }

    public void start() {
        Set<Region> regionSet = new TreeSet<>();
        try (InputStream input = getClass().getResourceAsStream("/ipstock.20140918")) {
            int max = 8 * 1024 * 1024;
            ByteBuffer buffer = ByteBuffer.allocate(max);
            byte[] bytes = buffer.array();
            int limit = 0, read ;
            while((read = input.read(bytes, limit, 8 * 1024)) != -1) {
                limit += read;
            }
            buffer.limit(limit);
            int version = buffer.getInt();
            int size = buffer.getInt();
            logger.info("ipstock version: {}, size: {}", version, size);
            byte[] regionId = new byte[8];
            while(buffer.hasRemaining()){
                int startIp = buffer.getInt();
                int endIp = buffer.getInt();
                buffer.get(regionId);
                Region region = new Region(startIp, endIp, new String(regionId));
                regionSet.add(region);
                buffer.position(buffer.position() + 5);
                int len = buffer.getInt();
                buffer.position(buffer.position() + len);
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("parse ipstock error", e);
        }
        regions = regionSet.toArray(new Region[0]);
    }



    static class Region implements Comparable<Region>{
        final int startIp;
        final int endIp;
        final String regionId;

        public Region(int startIp, int endIp, String regionId) {
            this.startIp = startIp;
            this.endIp = endIp;
            this.regionId = regionId;
        }

        public int getStartIp() {
            return startIp;
        }

        public int getEndIp() {
            return endIp;
        }

        public String getRegionId() {
            return regionId;
        }

        @Override
        public int compareTo(Region o) {
            return Integer.valueOf(startIp).compareTo(o.startIp);
        }
    }

    public static void main(String[] args) throws IOException {
        Ipstock ipstock = new Ipstock();
        ipstock.start();

        List<String> lines = Files.readAllLines(Paths.get("e:\\ipcount"));
        System.out.println(lines.size());
        Map<String, List<String[]>> collect = lines.stream().map(l -> {
            String[] larry = l.split("\t");
            String ip = larry[0];
            String count = larry[1];
            String region = ipstock.findRegionId(ip);
            return new String[]{region, count};
        }).collect(Collectors.groupingBy((String[] a) -> a[0]));

        List<String> nl = new ArrayList<>();
        collect.forEach((r,l) -> {
            Integer c = l.stream().map(t -> Integer.parseInt(t[1])).collect(Collectors.summingInt(t -> t));
            nl.add(String.format("%s\t%d",r,c));
        });
        nl.stream().forEach(System.out::println);
        Files.write(Paths.get("e:\\regioncount"),nl, StandardOpenOption.CREATE,StandardOpenOption.WRITE);

    }
}
